<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Redux Demo</h1>
    <hr />

    <div>
      <p>当前 count: <span id="span"></span></p>
      <button id="btn1">increment</button>
      <button id="btn2">decrement</button>
      <button id="btn3">当奇数时再加一</button>
      <button id="btn4">隔一秒再加一</button>
    </div>

    <!-- 引入 Redux 核心库 -->
    <script src="./lib/redux.js"></script>
    <script>
      /**
       * Redux 核心概念
       *    1. action
       *        概念：就是一个包含有 type 属性的普通对象
       *    2. state
       *        概念：仓库中存放的状态数据
       *    3. reducer
       *        概念：一个用于产出 state 的纯函数
       *    4. store
       *        概念：核心，仓库
       *    5. store.getState()
       *        概念：获取当前 state 数据的函数
       *    6. store.dispatch(action)
       *        概念：派发动作
       *    7. store.subscribe(listener)
       *        概念：订阅store的更新，当更新时，会触发 listener (订阅者)
       */

      // 定义一个 store 中 state 的初始值
      const initialState = {
        msg: "~",
        count: 1,
      };

      // 0. 定义一个 reducer 纯函数，他是生成 仓库state数据与修改state数据的地方
      //     1. 他是一个函数，接受两个参数
      //        state     - 上一次仓库中state的数据
      //        action    - dispatch 派发一个动作时的 动作内容
      //     2. 他需要有返回值，返回值就是 store 的 state 数据
      //     3. 他的触发时机
      //        1. 默认会在创建store的时候触发一次。这时：
      //           state - 为 undefined
      //           action - 为 redux 生成的随机动作
      //        2. 后续当有新的动作被派发时触发，这时：
      //           state - 为上一次 store 中的 state 数据
      //           action - 为 这次的动作。
      //     4. 他需要是一个纯函数
      //        1. 相同输入一定产生相同的输出
      //        2. 不能修改外部数据源，也不能修改参数。
      //        3. 不能包含有副作用: 必须是同步的，不能有异步代码、修改DOM的操作

      function reducer(state = initialState, action) {
        console.log("state", state);
        console.log("action", action);

        // 根据 action.type 不同，来处理不同的 数据
        switch (action.type) {
          case "INCREMENT":
            // state.count++; // 不行不OK绝对不允许

            // 而是基于现有state构造出一份全新的对象，并return。return 的内容就是最新的 state
            return {
              ...state, // PS: 需要保留现有字段，否则会有问题的。
              count: state.count + 1,
            };

          case "DECREMENT":
            return {
              ...state,
              count: state.count - 1,
            };
          // state.count--;
          // return state;

          default:
            return state;
        }
      }

      // 1. 使用 Redux.createStore() 来创建 store
      //    store 有三个核心的API
      //    1. store.getState()           返回当前仓库中 state 数据
      //    2. store.dispatch(action)     派发一个动作
      //    3. store.subscribe(listener)  订阅store数据的变化，传递的 listener 是一个订阅函数，当 store 中数据变化之后，会触发该 listener 函数
      const store = Redux.createStore(
        reducer,
        window.__REDUX_DEVTOOLS_EXTENSION__ &&
          window.__REDUX_DEVTOOLS_EXTENSION__()
      );

      // 2. 创建一个 render 函数，用于渲染页面
      function render() {
        // 获取最新的 store 中 state 数据
        const state = store.getState(); // { msg: '~', count: 1 }
        document.querySelector("#span").innerHTML = state.count;
      }
      // 3. 默认调用一次 render
      render();
      // 订阅仓库数据的变化，然后再次调用render
      store.subscribe(render);

      // 4. 页面的事件处理
      btn1.onclick = function () {
        // "INCREMENT" | "DECREMENT" 叫做魔鬼字符串，需要复制来用，避免写错之后没有报错也没有效果
        store.dispatch({ type: "INCREMENT" });
        // render();
      };

      btn2.onclick = function () {
        store.dispatch({ type: "DECREMENT" });
        // render();
      };

      btn3.onclick = function () {
        const count = store.getState().count;
        if (count % 2 !== 0) {
          store.dispatch({ type: "INCREMENT" });
          // render();
        }
      };

      btn4.onclick = function () {
        setTimeout(() => {
          store.dispatch({ type: "INCREMENT" });
          // render();
        }, 1000);
      };

      // ================== 万能的分割线 =====================================

      // console.log("store", store);

      // console.log("store.getState()", store.getState()); // { msg: '~', count: 1 }

      // store.subscribe(() => {
      //   console.log("store 数据边改了");
      // });

      // setTimeout(() => {
      //   // 派发一个动作
      //   store.dispatch({ type: "INCREMENT" });
      //   // 再次获取最新的 state 数据
      //   console.log("store.getState()", store.getState()); // { msg: '~', count: 1 }
      // }, 3000);
    </script>
  </body>
</html>
